//
//  UIColor+SGExtension.swift
//  QingLiuSwift
//
//  Created by xyanl on 2023/7/13.
//

import Foundation
import UIKit

/// 渐变方向
enum YLGradientDirection {
    /// 水平 (左 -> 右)
    case horizontal
    /// 垂直 (上 -> 下)
    case vertical
    /// 主对角线方向渐变(左上角->右下角)
    case upDiagonalLine
    /// 副对角线方向渐变(左下角->右上角)
    case downDiagonalLine
    /// 自定义, (起始, 终止) 
    case custom(CGPoint, CGPoint)
    
    public func point() -> (CGPoint, CGPoint) {
        switch self {
        case .horizontal:
            return (CGPoint(x: 0, y: 0), CGPoint(x: 1, y: 0))
        case .vertical:
            return (CGPoint(x: 0, y: 0), CGPoint(x: 0, y: 1))
        case .upDiagonalLine:
            return (CGPoint(x: 0, y: 0), CGPoint(x: 1, y: 1))
        case .downDiagonalLine:
            return (CGPoint(x: 1, y: 0), CGPoint(x: 0, y: 1))
        case .custom(let startPoint, let endPoint):
            return (startPoint, endPoint)
        }
    }
    
}

public extension UIColor {
    
    static func colorScheme(default: UIColor, dark: UIColor? = nil, light: UIColor? = nil) -> UIColor {
        if #available(iOS 13.0, *) {
            return UIColor { (traits) -> UIColor in
                switch traits.userInterfaceStyle {
                case .dark: return dark ?? `default`
                case .light: return light ?? `default`
                case .unspecified: return `default`
                @unknown default: return `default`
                }
            }
        } else { return `default` }
    }
    
    /// UIColor 转 UIImage
    func toImage() -> UIImage? {
        UIGraphicsBeginImageContext(CGSize(width: 1.0, height: 1.0))
        guard let contextRef: CGContext = UIGraphicsGetCurrentContext() else {
            return nil
        }
        
        contextRef.setFillColor(self.cgColor)
        contextRef.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        guard let img: UIImage = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        UIGraphicsEndImageContext()
        return img
    }
    
    /// SwifterSwift: Hexadecimal value string (read-only).
    var hexString: String {
        let components: [Int] = {
            let comps = cgColor.components!
            let components = comps.count == 4 ? comps : [comps[0], comps[0], comps[0], comps[1]]
            return components.map { Int($0 * 255.0) }
        }()
        return String(format: "#%02X%02X%02X", components[0], components[1], components[2])
    }
    
    /// 获取当前透明度
    var alpha: CGFloat {
        cgColor.alpha
    }
    
    
    /// 初始化UIColor
    /// - Parameters:
    ///   - red: 红
    ///   - green: 绿
    ///   - blue: 蓝
    ///   - alpha: 透明度
    convenience init?(red: Int, green: Int, blue: Int, alpha: CGFloat = 1) {
        guard red >= 0 && red <= 255 else { return nil }
        guard green >= 0 && green <= 255 else { return nil }
        guard blue >= 0 && blue <= 255 else { return nil }
        let trans = max(0, min(alpha, 1))
        self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: trans)
    }
    
  
    /// 初始化UIColor
    /// - Parameters:
    ///   - hexString: 十六进制
    ///   - alpha: 透明度(默认:1)
    convenience init(hex string: String, _ alpha: CGFloat = 1.0) {
        // 统一变大写
        var colorString = string.uppercased()
        // 删除空格
        colorString = colorString.replacingOccurrences(of: " ", with: "")
        // 替换头部
        colorString = colorString.replacingOccurrences(of: "#", with: "")
        colorString = colorString.replacingOccurrences(of: "0X", with: "")
        
        guard colorString.count == 6 else {
            self.init(white: 1.0, alpha: 0.0)
            print("[SpadgerColor] 请检查 hex 字符串长度是否正确")
            return
        }
        
        guard let intCode = Int(colorString, radix: 16) else {
            self.init(white: 1.0, alpha: 0.0)
            return
        }
        
        self.init(
            red: CGFloat((intCode >> 16) & 0xFF) / 255.0,
            green: CGFloat((intCode >> 8) & 0xFF) / 255.0,
            blue: CGFloat((intCode) & 0xFF) / 255.0,
            alpha: max(0, min(alpha, 1))
        )
    }
    
    /// 添加红色
    func withAddedRed(_ addedRed: CGFloat) -> UIColor {
        var red: CGFloat = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat = 0.0
        var alpha: CGFloat = 0.0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return UIColor(red: min( red + addedRed, 1.0 ), green: green, blue: blue, alpha: alpha)
    }
    
    /// 添加绿色
    func withAddedGreen(_ addedGreen: CGFloat) -> UIColor {
        var red: CGFloat = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat = 0.0
        var alpha: CGFloat = 0.0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return UIColor(red: red, green: min( green + addedGreen, 1.0 ), blue: blue, alpha: alpha)
    }
    
    /// 添加蓝色
    func withAddedBlue(_ addedBlue: CGFloat) -> UIColor {
        var red: CGFloat = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat = 0.0
        var alpha: CGFloat = 0.0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return UIColor(red: red, green: green, blue: min( blue + addedBlue, 1.0 ), alpha: alpha)
    }
    
    /// 修改透明度
    /// - Parameter alpha: 透明度
    func setAlpha(_ alpha: CGFloat) -> UIColor {
        withAlphaComponent(alpha)
    }
    
    
    /// 调整普通模式
    /// - Parameter percentage: 百分比
    /// - Returns: 颜色
    func lighter(by percentage: CGFloat) -> UIColor {
        var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, alpha: CGFloat = 0.0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return UIColor(
            red: min(red + percentage, 1.0),
            green: min(green + percentage, 1.0),
            blue: min(blue + percentage, 1.0),
            alpha: alpha
        )
    }
    
    
    /// 调整暗模式
    /// - Parameter percentage: 百分比
    /// - Returns: 颜色
    func darker(by percentage: CGFloat) -> UIColor {
        var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, alpha: CGFloat = 0.0
        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return UIColor(
            red: max(red - percentage, 0.0),
            green: max(green - percentage, 0.0),
            blue: max(blue - percentage, 0.0),
            alpha: alpha
        )
    }
    
    
    /// 调整亮度
    /// - Parameter percentage: 百分比
    /// - Returns: 颜色
    func adjustBrightness(by percentage: CGFloat) -> UIColor {
        var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
            if b < 1.0 {
                /**
                 Below is the new part, which makes the code work with black as well as colors
                 */
                return UIColor(
                    hue: h,
                    saturation: s,
                    brightness: b == 0.0 ? max(min(b + percentage/100, 1.0), 0.0) : max(min(b + (percentage/100.0)*b, 1.0), 0,0),
                    alpha: a)
                
            } else {
                return UIColor(
                    hue: h,
                    saturation: min(max(s - (percentage/100.0)*s, 0.0), 1.0),
                    brightness: b,
                    alpha: a
                )
            }
        }
        return self
    }
    
    /// 随机色
    static var randomColor: UIColor {
        let red = Int.random(in: 0...255)
        let green = Int.random(in: 0...255)
        let blue = Int.random(in: 0...255)
        return UIColor(red: red, green: green, blue: blue)!
    }
    
    convenience init(light: UIColor, dark: UIColor) {
        self.init { trainCollection in
            switch trainCollection.userInterfaceStyle {
            case .light, .unspecified:
                return light
            case .dark:
                return dark
            default:
                return light
            }
        }
    }
}

extension UIColor {
    
    /// 渐变色
    /// - Parameters:
    ///   - colors: 颜色
    ///   - locations: 渐变起始位置,默认:nil 平均分配
    ///   - startPoint: 起始位置坐标 默认:左上角坐标(0, 0)
    ///   - endPoint: 终止位置坐标 默认:右下角坐标(1, 1)
    ///   - rect: view.bouns
    /// - Returns: 渐变颜色
    static func gradient(_ direction: YLGradientDirection = .horizontal, colors: [UIColor], locations: [NSNumber]? = nil, rect: CGRect) -> UIColor {
        
        let gradientLayer = UIColor.gradientLayer(direction, colors: colors, locations: locations, rect: rect)
        
        UIGraphicsBeginImageContext(rect.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        return UIColor.init(patternImage: image)
    }
    
    
    /// 设置渐变色图层
    /// - Parameters:
    ///   - direction: 渐变方向
    ///   - colors: 渐变的颜色数组（颜色的数组）
    ///   - locations: 设置渐变颜色的终止位置，这些值必须是递增的，数组的长度和 colors 的长度最好一致
    ///   - rect: view.bouns
    /// - Returns: 渐变色图层
    static func gradientLayer(_ direction: YLGradientDirection = .horizontal, colors: [UIColor], locations: [NSNumber]? = nil, rect: CGRect) -> CAGradientLayer {
        let gradientLayer = CAGradientLayer.init()
        
        // 渐变颜色
        let cgColors: NSMutableArray = NSMutableArray() 
        colors.forEach { color in
            cgColors.add(color.cgColor)
        }
        gradientLayer.colors = cgColors as? [Any]
        
        // 设置渐变颜色的终止位置，这些值必须是递增的，数组的长度和 colors 的长度最好一致
        
        if locations != nil {
            gradientLayer.locations = locations
        } else {
            var newLocations: [NSNumber] = []
            for index in 0..<cgColors.count {
                newLocations.append(NSNumber(value: 1.0 / Double(cgColors.count - 1) * Double(index)))
            }
            gradientLayer.locations = newLocations
        }
        
        // 设置渲染的起始结束位置（渐变方向设置）
        gradientLayer.startPoint = direction.point().0
        gradientLayer.endPoint = direction.point().1
        // CAGradientLayer的控件大小
        gradientLayer.frame = rect
        
        return gradientLayer
    }
}
